﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace RescueApplication
{
    public partial class Form1 : Form
    {

        public delegate void UpdateTextCallback(string text);
        private delegate void ReconnectCallback();//Handle Cross-Thread exception.
        const int Max = 39000, Min = 26000;
        joyStick jStick;
        string direction = "null";
        public Client client;
        public Server server;
        bool checkSCGo = false;
        bool checkJoyGo = false;
        bool checkWebGo = false;
        public Form1()
        {
            InitializeComponent();
            initJoy();
            txtTimer1.Text = timer1.Interval.ToString();
            txtTimer2.Text = timer2.Interval.ToString();
            button3.Enabled = false;
            button1.Enabled = false;
        }

        private void initJoy()
        {
            jStick = new joyStick(this.Handle);
            try
            {
                string[] numJoy = jStick.FindJoysticks();
                if (numJoy.GetLongLength(0) != 0)
                    comboBox1.Items.AddRange(numJoy);
            }
            catch (Exception ex)
            {
                comboBox1.Items.Insert(0, "NULL (Plese re program)");
                MessageBox.Show("Must Connect join \n Error Code : " + ex.Message);
            }

        }

        public bool IsHex//Check if 'Hex' checkbox is checked
        {
            get { return checkBox1.Checked; }
        }

        public bool IsNoPrintOnReceiving//Check if 'No Print On Receiving' checkbox is checked
        {
            get { return checkBox2.Checked; }
        }

        private bool IsValidIPAddress(string ipaddr)//Validate the input IP address
        {
            try
            {
                IPAddress.Parse(ipaddr);
                return true;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "IsValidIPAddress Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        public void UpdateText(string text)//Update the text on textBox1
        {
            if (this.textBox1.InvokeRequired)
            {
                UpdateTextCallback temp = new UpdateTextCallback(UpdateText);
                this.Invoke(temp, new object[] { text });
            }
            else
            {
                string str = "";
                if (checkBox1.Checked == false)
                {
                    if (radioButton1.Checked == true) str = "\r\nClient said: (@" + DateTime.Now.ToString() + ")\r\n" + text;
                    else if (radioButton2.Checked == true) str = "\r\nServer said: (@" + DateTime.Now.ToString() + ")\r\n" + text;
                }
                else
                {
                    //Revise required!
                    if (radioButton1.Checked == true) str = "\r\nClient said: (@" + DateTime.Now.ToString() + ")\r\n" + text;
                    else if (radioButton2.Checked == true) str = "\r\nServer said: (@" + DateTime.Now.ToString() + ")\r\n" + text;
                }

                textBox1.AppendText(str);
            }
        }

        private void button2_Click_1(object sender, EventArgs e)
        {
            string ipAddr = textBox3.Text;
            string port = textBox4.Text;
            if (IsValidIPAddress(ipAddr) == true)
            {
                if (radioButton1.Checked == true)//Server Mode
                {
                    try
                    {
                        if (server == null)
                            server = new Server(this);

                        server.Connect(ipAddr, port);

                        button2.Enabled = false;
                        button3.Enabled = true;
                        textBox2.Focus();
                        checkSCGo = true;
                        button1.Enabled = true;
                    }
                    catch (SocketException se)
                    {
                        MessageBox.Show("Server Connect Error.\r\n" + se.ToString());
                    }
                }
                else if (radioButton2.Checked == true)//Client Mode
                {
                    try
                    {
                        if (client == null)
                            client = new Client(this);

                        client.Connect(ipAddr, port);

                        string data = "Hello, I'm a Client";
                        client.Send(Encoding.GetEncoding(Constant.SimplifiedChineseCode).GetBytes(data));
                        textBox1.AppendText("\r\nClient said: (@" + DateTime.Now.ToString() + ")\r\n" + data + "\r\n");
                        button2.Enabled = false;
                        button3.Enabled = true;
                        textBox2.Focus();
                        checkSCGo = true;
                        button1.Enabled = true;
                    }
                    catch (SocketException se)
                    {
                        MessageBox.Show("Client Connect Error.\r\n" + se.ToString());
                    }
                }
            }
            else
            {
                MessageBox.Show("Invalid IP address input.");
            }
        } // Clinet-Server connect

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox2.Text != "")
            {
                if (radioButton1.Checked == true)//Server Mode
                {
                    try
                    {
                        if (server != null)
                        {
                            byte[] bytes = Encoding.GetEncoding(Constant.SimplifiedChineseCode).GetBytes(textBox2.Text);
                            server.Send(bytes);
                            string str = "";
                            if (checkBox1.Checked == false)//Display data in text
                            {
                                str = "\r\nServer said: (@" + DateTime.Now.ToString() + ")\r\n" + textBox2.Text;
                            }
                            else//Display data in Hex
                            {
                                str = "\r\nServer said: (@" + DateTime.Now.ToString() + ")\r\n";
                                for (int i = 0; i < bytes.Length; i++)
                                {
                                    str += (bytes[i].ToString("X").Length == 2 ? bytes[i].ToString("X") : "0" + bytes[i].ToString("X")) + " ";
                                }
                            }
                            //textBox1.AppendText(str + "\r\n");
                            //textBox2.Clear();
                        }
                    }
                    catch (SocketException se)
                    {
                        MessageBox.Show("Server send error!\r\n" + se.Message);
                    }
                }
                else if (radioButton2.Checked == true)//Client Mode
                {
                    try
                    {
                        if (client != null)
                        {
                            byte[] bytes = Encoding.GetEncoding(Constant.SimplifiedChineseCode).GetBytes(textBox2.Text);
                            client.Send(bytes);
                            string str = "";
                            if (checkBox1.Checked == false)//Display data in text
                            {
                                str = "\r\nClient said: (@" + DateTime.Now.ToString() + ")\r\n" + textBox2.Text;
                            }
                            else//Display data in Hex
                            {
                                str = "\r\nClient said: (@" + DateTime.Now.ToString() + ")\r\n";
                                for (int i = 0; i < bytes.Length; i++)
                                {
                                    str += (bytes[i].ToString("X").Length == 2 ? bytes[i].ToString("X") : "0" + bytes[i].ToString("X")) + " ";
                                }
                            }
                            //textBox1.AppendText(str + "\r\n");
                            //textBox2.Clear();
                        }
                    }
                    catch (SocketException se)
                    {
                        MessageBox.Show("Client send error!\r\n" + se.Message);
                    }
                }
            }
        } // Send packet

        private void btnConnect_Click(object sender, EventArgs e)
        {
            int indexCmb = comboBox1.SelectedIndex;
            if (indexCmb == -1)
            {
                MessageBox.Show("Should select joy list first","Error");
            }
            else
            {
                if (btnConnect.Text == "Connect")
                {
                    string[] joyName = jStick.FindJoysticks();
                    jStick.AcquireJoystick(joyName[indexCmb]);
                    jStick.UpdateStatus();
                    btnConnect.Text = "Disconnect";
                    toolStripStatusLabel2.Text = "Joy : Connected | Update :[" + timer1.Interval.ToString() + "ms]";
                    checkJoyGo = true;
                    timer1.Start();

                }
                else if(btnConnect.Text == "Disconnect")
                {
                    jStick.ReleaseJoystick();
                    timer1.Stop();
                    btnConnect.Text = "Connect";
                    toolStripStatusLabel2.Text = "Joy : [Disconnected] | no update]";
                    checkJoyGo = false;
                }
            }

        } // Joy connect

        
        private string calJoyPOV(joyStick js)
        {
            String dataBuf = "";
            switch (js.Pov)
            {
                case -1:
                    dataBuf += "o";
                    break;
                case 0:
                    dataBuf += "w";
                    break;
                case 4500:
                    dataBuf += "e";
                    break;
                case 9000:
                    dataBuf += "d";
                    break;
                case 13500:
                    dataBuf += "c";
                    break;
                case 18000:
                    dataBuf += "s";
                    break;
                case 22500:
                    dataBuf += "z";
                    break;
                case 27000:
                    dataBuf += "a";
                    break;
                case 31500:
                    dataBuf += "q";
                    break;
            }


            return dataBuf;
        }

        private string calCommand(joyStick js)
        {
            string txtData = convertBoolToBinary(js.Buttons);
            double speed;
            
            //txtData += "[";
            if ((js.JoyAnalogButtons[0] < Max && js.JoyAnalogButtons[0] > Min) && (js.JoyAnalogButtons[1] < Max && js.JoyAnalogButtons[1] > Min))
            {
                txtData += "1xxx";
            }
            else if ((js.JoyAnalogButtons[0] < Max && js.JoyAnalogButtons[0] > Min) && js.JoyAnalogButtons[1] < Min) // TOP
                txtData += "0000";
            else if ((js.JoyAnalogButtons[0] < Max && js.JoyAnalogButtons[0] > Min) && js.JoyAnalogButtons[1] > Max) // DOWN
                txtData += "0100";
            else if ((js.JoyAnalogButtons[1] < Max && js.JoyAnalogButtons[1] > Min) && js.JoyAnalogButtons[0] < Min) // Left
                txtData += "0110";
            else if ((js.JoyAnalogButtons[1] < Max && js.JoyAnalogButtons[1] > Min) && js.JoyAnalogButtons[0] > Max) // Left
                txtData += "0010";
            else if (js.JoyAnalogButtons[0] < Min && js.JoyAnalogButtons[1] < Min) // Left top
                txtData += "0111";
            else if (js.JoyAnalogButtons[0] > Max && js.JoyAnalogButtons[1] < Min) // Right top
                txtData += "0001";
            else if (js.JoyAnalogButtons[0] < Min && js.JoyAnalogButtons[1] > Max) // Bottom left
                txtData += "0101";
            else if (js.JoyAnalogButtons[0] > Max && js.JoyAnalogButtons[1] > Max) // bottom right
                txtData += "0011";
            //txtData += "]";
            speed = Math.Ceiling(Math.Sqrt(Math.Pow((js.JoyAnalogButtons[0]-32768), 2) + Math.Pow((js.JoyAnalogButtons[1]-32768),2)));

            if(speed < 10000)
            {
                txtData += 0.ToString();
                txtData += 0.ToString();
            }
            else if(speed > 32768)
            {
                txtData += 99.ToString();
            }
            else if(speed < 12100)
            {
                txtData += 0.ToString();
                txtData += (Math.Ceiling(((speed-10000)/22768)*99)).ToString();
            }else 
                txtData += (Math.Ceiling(((speed-10000)/22768)*99)).ToString();
            
            //txtData += "" + cameraJoyR(jStick) + "";
            txtData += calJoyPOV(jStick);
            return txtData;
        }

        private string cameraJoyR(joyStick js)
        {
            string cmdJoy = "";
                if ((js.JoyAnalogButtons[3] < Max && js.JoyAnalogButtons[3] > Min) && (js.JoyAnalogButtons[4] < Max && js.JoyAnalogButtons[4] > Min))
                {
                    cmdJoy += "1xxx";
                }
                else if ((js.JoyAnalogButtons[3] < Max && js.JoyAnalogButtons[3] > Min) && js.JoyAnalogButtons[4] < Min) // TOP
                    cmdJoy += "0000";
                else if ((js.JoyAnalogButtons[3] < Max && js.JoyAnalogButtons[3] > Min) && js.JoyAnalogButtons[4] > Max) // DOWN
                    cmdJoy += "0100";
                else if ((js.JoyAnalogButtons[4] < Max && js.JoyAnalogButtons[4] > Min) && js.JoyAnalogButtons[3] < Min) // Left
                    cmdJoy += "0110";
                else if ((js.JoyAnalogButtons[4] < Max && js.JoyAnalogButtons[4] > Min) && js.JoyAnalogButtons[3] > Max) // right
                    cmdJoy += "0010";
                else if (js.JoyAnalogButtons[3] < Min && js.JoyAnalogButtons[4] < Min) // Left top
                    cmdJoy += "0111";
                else if (js.JoyAnalogButtons[3] > Max && js.JoyAnalogButtons[4] < Min) // Right top
                    cmdJoy += "0001";
                else if (js.JoyAnalogButtons[3] < Min && js.JoyAnalogButtons[4] > Max) // Bottom left
                    cmdJoy += "0101";
                else if (js.JoyAnalogButtons[3] > Max && js.JoyAnalogButtons[4] > Max) // bottom right
                    cmdJoy += "0011";
            return cmdJoy;
        }

        private void doCamera()
        {
            string cmd = cameraJoyR(jStick);
            if (checkWebGo)
            {
                try
                {
                    if (cmd == "1xxx")
                    {
                        if (direction != "null")
                        {
                            if (direction == "left")
                                webBrowser1.Navigate(new Uri("javascript:left_onmouseup();"));
                            else if (direction == "right")
                                webBrowser1.Navigate(new Uri("javascript:right_onmouseup();"));
                            else if (direction == "up")
                                webBrowser1.Navigate(new Uri("javascript:up_onmouseup();"));
                            else if (direction == "down")
                                webBrowser1.Navigate(new Uri("javascript:down_onmouseup();"));
                        }
                        direction = "null";
                    }
                    else
                    {
                        if (direction == "null")
                        {
                            if (cmd == "0110")
                            {
                                webBrowser1.Navigate(new Uri("javascript:left_onmousedown();"));
                                direction = "left";
                            }
                            else if (cmd == "0010")
                            {
                                webBrowser1.Navigate(new Uri("javascript:right_onmousedown();"));
                                direction = "right";
                            }
                            else if (cmd == "0000")
                            {
                                webBrowser1.Navigate(new Uri("javascript:up_onmousedown();"));
                                direction = "up";
                            }
                            else if (cmd == "0100")
                            {
                                webBrowser1.Navigate(new Uri("javascript:down_onmousedown();"));
                                direction = "down";
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Error Joy decoder");
                }
                
            }
        }

        private string convertBoolToBinary(bool[] data)
        {
            string txtData = "";
            int size = data.Length;
            //txtData = data.Length.ToString() + " : ";
            for (int i = 0; i < 8; i++)
            {
                if (data[i])
                    txtData += "1";
                else
                    txtData += "0";
            }
            return txtData;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            jStick.UpdateStatus();
            txtOpCode.Text = calCommand(jStick);
            doCamera();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            
            string dta = calCommand(jStick);
            if (dta != "")
            {
                if (radioButton2.Checked == true)//Client Mode
                {
                    try
                    {
                        if (client != null)
                        {
                            //byte[] bytes = Encoding.GetEncoding(Constant.SimplifiedChineseCode).GetBytes(dta);
                            byte[] bytes = Encoding.GetEncoding(Constant.SimplifiedChineseCode).GetBytes(calJoyPOV(jStick));
                            client.Send(bytes);
                        }
                    }
                    catch (SocketException se)
                    {
                        timer2.Stop();
                        timer1.Stop();
                        button2.Enabled = false;
                        button3.Enabled = true;
                        MessageBox.Show("Client send error! Socket error \r\n" + se.Message);
                    }
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (radioButton1.Checked == true)//Server Mode
            {
                server.Disconnect();
                if (button2.Enabled == false)
                {
                    button2.Enabled = true;
                    button3.Enabled = false;
                }
            }
            else if (radioButton2.Checked == true)//Client Mode
            {
                client.Disconnect();
                if (button2.Enabled == false)
                {
                    button2.Enabled = true;
                    button3.Enabled = false;
                }
            }
            button1.Enabled = false;
            timer2.Stop();
            timer1.Stop();
        }

        private void textBox2_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                button1_Click(sender, (EventArgs)e);//Send
            }
        }

        private void textBox2_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (textBox2.Lines.Length > 0)
                    textBox2.Lines = new string[] { };
            }
        }

        private void btnTimerSet_Click(object sender, EventArgs e)
        {
            try
            {
                timer1.Interval = int.Parse(txtTimer1.Text);
                timer2.Interval = int.Parse(txtTimer2.Text);
            }
            catch (Exception)
            {
                MessageBox.Show("Error", "Wrong input");
            }
            
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            textBox1.Clear();
            textBox2.Clear();
            txtTimer1.Text = "1";
            txtTimer2.Text = "100";
        }

        private void btnWebGo_Click(object sender, EventArgs e)
        {
            if (checkJoyGo == true && checkSCGo == true)
            {
                //checkWebGo = true;
                timer2.Start();
            }
            else
                MessageBox.Show("Check !\n-Joy\n-Server,Client", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            
        }
        
        private void informationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm abt = new AboutForm();

            abt.ShowDialog();
            abt.Dispose();

        }

        private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e)
        {

        }



    }

    public class KeyValuePair
    {
        public Socket socket;
        public byte[] dataBuffer = new byte[1];
    }

    public class Constant
    {
        //Simplified Chinese Code
        public static string SimplifiedChineseCode = "GB18030"; //"GB2312";

        //Software Version 'Major.Minor.Bug.Build'
        //public const string SOFTWAREVERSION = "1.0";
        public const string SOFTWAREVERSION = "1.1";//Apr 15, 2009

    }
}
